#pragma once

#include<iostream>
#include<string>
#include<vector>
#include<unistd.h>
#include<queue>
#include<functional>
#include"thread.hpp"
#include"Log.hpp"
#include"LockGuard"

using namespace ThreadModle;
static const int gdefultnum=5;


template<typename T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeUpAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    void HandlerTask(const std::string &name)//因内含this指针与定义的无参函数类型不同但是不能定义成static，因调用的都是内部成员
    {
        while(true)
        {
            LockQueue();
            while(IsEmpty() && _isrunning)
            {
                _sleep_thread++;
                LOG(INFO,"thread %s sleep begin\n",name.c_str());
                Sleep();
                LOG(INFO,"thread %s wake up\n",name.c_str());
                _sleep_thread--;
            }
            if(IsEmpty()&&!_isrunning)
            {
                UnLockQueue();
                LOG(INFO,"thread %s quit\n",name.c_str());
                break;
            }
            T t=_task_queue.front();
            _task_queue.pop();
            UnLockQueue();
            t();//处理任务

            // LOG(DEBUG,"hander task : %s\n",t.Result().c_str());
        }
    }

    ThreadPool(int thread_num=gdefultnum):
    _thread_num(thread_num),
    _isrunning(false),
    _sleep_thread(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }

    ThreadPool(const ThreadPool<T>& )=delete;//删除拷贝构造
    void operator=(const ThreadPool<T>&)=delete;

    void Init()
    {
        func_t func=std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1);//将this指针跟函数进行强关联可以解决this作为参数的问题，第二个参数表示函数有除this外的一个参数
        for(int i=0;i<_thread_num;i++)
        {
            std::string threadname="thread-"+std::to_string(i+1);
            _threads.emplace_back(threadname,func);
            LOG(DEBUG,"construct thread obj done ,init %s sucess\n",threadname.c_str());
        }
    }

    void Start()
    {
        _isrunning=true;
        for(auto& threa:_threads)
        {
            threa.Start();
            LOG(DEBUG,"start thread %s done\n",threa.Name().c_str());
        }
    }
public:
    
    
    static ThreadPool *GetInstand()//访问了静态成员，所以此函数也需要设计成静态函数
    {
        if(_tp==nullptr)
        {
            LockGuard lock(&_sig_mutex);
            if(_tp==nullptr)
            {
                LOG(INFO,"create thread pool done\n");
                _tp=new ThreadPool<T>();
                _tp->Init();
                _tp->Start();
            }
            else
            {
                LOG(INFO,"get thread pool done\n");
            }
        }
        else
        {
            LOG(INFO,"get thread pool done\n");
        }
        return _tp;
    }
    void Stop()
    {   
        LockQueue();
        _isrunning=false;
        WakeUpAll();
        UnLockQueue();
        LOG(INFO,"stop thread pool sucess\n");
    }
    void Equeue(const T &in)
    {
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(in);
            if(_sleep_thread>0)WakeUp();
        }
        UnLockQueue();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    int _thread_num;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    bool _isrunning;
    int _sleep_thread;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    //volatile static ThreadPool* _tp;//volatile 防止编译器做内存级优化，每次都会从内存中获取此变量
    static ThreadPool* _tp;//类内静态成员需要在外部初始化,单例模式的类对象指针
    static pthread_mutex_t _sig_mutex;
};

template<typename T>
ThreadPool<T> *ThreadPool<T>::_tp=nullptr;

template<typename T>
pthread_mutex_t ThreadPool<T>::_sig_mutex=PTHREAD_MUTEX_INITIALIZER;